package org.merck.mrl;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;

import javaFlacEncoder.FLAC_FileEncoder;

import javax.net.ssl.HttpsURLConnection;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.CoolBar;
import org.eclipse.swt.widgets.CoolItem;
import org.eclipse.swt.widgets.Display;

import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.json.simple.JSONValue;
import org.json.simple.parser.ContainerFactory;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

public class Ginger {
	private final static String BUTTON = "Button";
	private final static String TALK = " Talk ";
	private final static String STOP = " Stop ";
	private final static String TEXT = "Text";
	private final static String REPORT_ERROR = "Report Error";
	private final static String WAVE_FILE_PATH = "c:\\audio.wav";
	private final static String FLAC_FILE_PATH = "c:\\audio.flac";
	
	final static String googleSpeech2TextURL = "https://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&lang=en-US";
	final static String maluubaNPIURL = "http://napi.maluuba.com/v0/interpret?phrase=";
	final static String maluubaAPIKey = "&apikey=haQROlMTDKC7DpPH9Xvs2OPczekIN7Cp";

	static Semaphore stopped;
	protected static boolean running;
	private static String message;
	private static String utterance;

	private static SelectionListener mSelectionListener() {
		SelectionListener selectionListener = new SelectionListener() {

			@Override
			public void widgetDefaultSelected(SelectionEvent event) {
				if (event.widget instanceof Button) {
				} else
					return;

			}

			@Override
			public void widgetSelected(SelectionEvent event) {
				Button btn;
				System.out.println("Widget Selected "
						+ (event.widget instanceof Button));
				if (event.widget instanceof Button)
					btn = (Button) event.widget;
				else
					return;
				// Talk button pressed
				if (btn.getText().equalsIgnoreCase(TALK)) {
					// Disable the button to avoid further press
					btn.setEnabled(false);
					// Enable the stop Button which is by default disabled while
					// creation
					Button stopBtn = (Button) btn.getData(BUTTON);
					stopBtn.setEnabled(true);

					Text t = (Text) btn.getData(TEXT);
					//t.append("\n" + "Talk Button Pressed");
					try {
						stopped.acquire();
					} catch (InterruptedException e1) {

						e1.printStackTrace();
					}
					captureAudio();

				} else if (btn.getText().equalsIgnoreCase(STOP)) {
					// Disable the button to avoid further press
					btn.setEnabled(false);

					Text t = (Text) btn.getData(TEXT);
					//t.append("\n" + "Stop Button Pressed");
					running = false;
					try {
						stopped.acquire();
						recognize(t);
						stopped.release();
					} catch (IOException e1) {
						e1.printStackTrace();
					} catch (InterruptedException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
					// Enable the TALK Button
					Button startBtn = (Button) btn.getData(BUTTON);
					startBtn.setEnabled(true);
				}
			}

		};
		return selectionListener;
	}

	private static void captureAudio() {
		try {
			final AudioFormat format = getFormat();
			DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
			final TargetDataLine line = (TargetDataLine) AudioSystem
					.getLine(info);
			line.open(format);
			line.start();
			Runnable runner = new Runnable() {
				int bufferSize = (int) format.getSampleRate()
						* format.getFrameSize();
				byte buffer[] = new byte[bufferSize];
				private ByteArrayOutputStream out;

				public void run() {
					out = new ByteArrayOutputStream();
					running = true;
					try {
						while (running) {
							int count = line.read(buffer, 0, buffer.length);
							if (count > 0) {
								out.write(buffer, 0, count);
							}
						}

						byte audio[] = out.toByteArray();
						InputStream input = new ByteArrayInputStream(audio);
						final AudioFormat format = getFormat();
						final AudioInputStream ais = new AudioInputStream(
								input, format, audio.length
										/ format.getFrameSize());
						File wavFile = createNewFile(WAVE_FILE_PATH);
						AudioSystem.write(ais, AudioFileFormat.Type.WAVE,
								wavFile);
						;

						FLAC_FileEncoder flacEncoder = new FLAC_FileEncoder();

						File flacFile = createNewFile(FLAC_FILE_PATH);
						flacEncoder.encode(wavFile, flacFile);
						System.out.println("Flac File created");
						out.close();
						line.stop();
						line.close();
						stopped.release();

					} catch (IOException e) {
						System.err.println("I/O problems: " + e);
						System.exit(-1);
					}
				}
			};
			Thread captureThread = new Thread(runner);
			captureThread.start();
		} catch (LineUnavailableException e) {
			System.err.println("Line unavailable: " + e);
			System.exit(-2);
		}
	}

	private static File createNewFile(String fileName) {
		try {
			new File(fileName).delete();
		} catch (Exception e) {

		}
		File f = new File(fileName);
		try {
			f.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		return f;

	}

	private static void recognize(Text text) throws IOException {

		RandomAccessFile f = new RandomAccessFile(FLAC_FILE_PATH, "r");
		byte[] b = new byte[(int) f.length()];
		f.read(b);
		f.close();
		File file = new File(FLAC_FILE_PATH);
		file.delete();

		URL url = new URL(googleSpeech2TextURL);

		HttpsURLConnection connection = (HttpsURLConnection) url
				.openConnection();
		connection.setDoOutput(true);
		connection.setDoInput(true);
		connection.setInstanceFollowRedirects(false);
		connection.setRequestMethod("POST");
		connection.setRequestProperty("Content-Type",
				"audio/x-flac; rate=16000");
		connection.setRequestProperty("Content-Length",
				"" + Integer.toString(b.length));
		connection.setUseCaches(false);
		DataOutputStream outputStream = new DataOutputStream(
				connection.getOutputStream());
		outputStream.write(b);
		String line;
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				connection.getInputStream()));
		text.setText("");
		while ((line = reader.readLine()) != null) {
			System.out.println(line);
			message = line;
			text.append("\n" + line);
		}
		JSONParser parser = new JSONParser();
		ContainerFactory containerFactory = new ContainerFactory() {
			public List<Object> creatArrayContainer() {
				LinkedList<Object> l = new LinkedList<Object>();
				return l;
			}

			public Map<String, Object> createObjectContainer() {
				return new LinkedHashMap<String, Object>();
			}

		};

		try {
			Map<?, ?> json = (Map<?, ?>) parser
					.parse(message, containerFactory);
			Iterator<?> iter = json.keySet().iterator();
			System.out.println("==iterate result==");
			while (iter.hasNext()) {
				String key = (String) iter.next();
				System.out.println(key + "=>" + json.get(key));
				if (key.equalsIgnoreCase("hypotheses")) {
					List<?> hypothesesList = (List<?>) json.get(key);
					if (hypothesesList == null || hypothesesList.size() != 0) {
						Map<?, ?> hypotheses = (Map<?, ?>) hypothesesList
								.get(0);

						Iterator<?> iterator = hypotheses.keySet().iterator();

						while (iterator.hasNext()) {
							String hypKey = (String) iterator.next();
							if (hypKey.equalsIgnoreCase("utterance"))
								utterance = (String) hypotheses.get(hypKey);
							System.out.println(hypKey + "====>"
									+ hypotheses.get(hypKey));
						}
						System.out.println("==toJSONString()==");
						System.out.println(JSONValue.toJSONString(json));
						categorize(text);
					}
				}
			}

			
		} catch (ParseException pe) {
			System.out.println(pe);
		}

	}

	private static void categorize(Text text) throws IOException {
		String httpAddress = maluubaNPIURL + utterance.replaceAll(" ", "+")
				+ maluubaAPIKey;
		System.out.println(httpAddress);
		URL maluuba = new URL(httpAddress);
		URLConnection nAPI = maluuba.openConnection();
		BufferedReader in = new BufferedReader(new InputStreamReader(
				nAPI.getInputStream()));
		String inputLine;
		
		while ((inputLine = in.readLine()) != null) {
			System.out.println(inputLine);
			text.append("\n" + inputLine);
		}
		in.close();
	}

	private static AudioFormat getFormat() {
		float sampleRate = 16000;
		int sampleSizeInBits = 16;
		int channels = 1;
		boolean signed = true;
		boolean bigEndian = true;
		return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed,
				bigEndian);
	}

	public static void main(String[] args) {

		System.setProperty("proxyHost", "webproxy.merck.com");
		System.setProperty("proxyPort", "8080");
		Display display = new Display();
		Shell shell = new Shell(display);
		int width = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()
				.getMaximumWindowBounds().width;
		shell.setBounds(width - 600, 100, 600, 300);
		shell.setLayout(new GridLayout(1, false));
		CoolBar coolBar = new CoolBar(shell, SWT.BORDER);
		coolBar.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		final CoolItem item = new CoolItem(coolBar, SWT.DROP_DOWN);
		stopped = new Semaphore(1);

		Composite c = new Composite(coolBar, SWT.BALLOON);
		c.setLayout(new GridLayout(3, false));
		Button talkBtn = new Button(c, SWT.PUSH);
		talkBtn.setText(TALK);

		talkBtn.addSelectionListener(mSelectionListener());

		Button stopBtn = new Button(c, SWT.PUSH);
		stopBtn.setText(STOP);
		// Disable on start of the program
		stopBtn.setEnabled(false);
		stopBtn.addSelectionListener(mSelectionListener());

		Button errorBtn = new Button(c, SWT.PUSH);
		errorBtn.setText(REPORT_ERROR);
		// Disable on start of the program
		stopBtn.setEnabled(false);
		stopBtn.addSelectionListener(mSelectionListener());
		item.setControl(c);

		Control control = item.getControl();
		Point pt = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
		pt = item.computeSize(pt.x, pt.y);
		item.setSize(pt);

		// Text Box
		Text t = new Text(shell, SWT.MULTI | SWT.BORDER | SWT.WRAP
				| SWT.V_SCROLL);
		t.setLayoutData(new GridData(GridData.FILL_BOTH));
		t.setText("Ready ...");

		talkBtn.setData(BUTTON, stopBtn);
		stopBtn.setData(BUTTON, talkBtn);
		talkBtn.setData(TEXT, t);
		stopBtn.setData(TEXT, t);

		coolBar.pack();

		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
	}
}
